//
// Created by A4-28 on 2020/10/22.
//
#pragma once
#include "glm/glm.hpp"
#include "glm/gtx/quaternion.hpp"
#include "glm/gtc/matrix_transform.hpp"
#include "glm/gtx/euler_angles.hpp"
#include "quaternion.h"

namespace WF {

    enum Space {
        WORLD,
        LOCAL
    };

    struct Transform {
        glm::vec3 Position;
        glm::vec3 Rotation;
        glm::vec3 Scale;
        Space space = LOCAL;
        glm::vec3 Forward;
        glm::vec3 Right;
        glm::vec3 Up;
        glm::vec3 Axis = glm::vec3(0, 1, 0);
        bool isChange = true;
        glm::mat4 Matrix;
        glm::mat4 ViewMatrix;

        void SetPosition(glm::vec3 position) {
            isChange = true;
            Position = position;
        }

        glm::vec3 GetPosition() {
            return Position;
        }

        void SetRotation(glm::vec3 rotation) {
            isChange = true;
            Rotation = rotation;
        }

        glm::vec3 GetRotation() {
            return Rotation;
        }

        void SetScale(glm::vec3 scale) {
            isChange = true;
            Scale = scale;
        }

        glm::vec3 GetScale() {
            return Scale;
        }

        glm::vec3 GetForward(Space space) {
            if (space == LOCAL) {
                if (isChange) {
                    UpdateVector();
                }
                return Forward;
            } else {
                return glm::vec3(0, 0, 1);
            }
        }

        glm::vec3 GetRight(Space space) {
            if (space == LOCAL) {
                if (isChange) {
                    UpdateVector();
                }
                return Right;
            } else {
                return glm::vec3(1, 0, 0);
            }
        }

        glm::vec3 GetUp(Space space) {
            if (space == LOCAL) {
                if (isChange) {
                    UpdateVector();
                }
                return Up;
            } else {
                return glm::vec3(0, 1, 0);
            }
        }

        glm::mat4 GetMatrix() {
            if (isChange) {
                UpdateVector();
            }
            return Matrix;
        }

        glm::mat4 GetViewMatrix() {
            if (isChange) {
                ViewMatrix = glm::lookAt(Position, Position + Forward, Axis);
            }
            return ViewMatrix;
        }

        void UpdateVector() {
            Forward.x = glm::cos(Rotation.x) * glm::sin(Rotation.y);
            Forward.y = glm::sin(Rotation.x);
            Forward.z = glm::cos(Rotation.x) * glm::cos(Rotation.y);
            Right = glm::normalize(glm::cross(Forward, Axis));
            Up = glm::normalize(glm::cross(Forward, Right));
            Forward = glm::normalize(Forward);
            glm::mat4 translate = glm::translate(glm::mat4(1.0f), Position);
            glm::mat4 rotate = Quaternion::EulerToMatrix(Rotation);
            glm::mat4 scale = glm::scale(glm::mat4(1.0f), Scale);
            Matrix = translate * rotate * scale;
            isChange = false;
        }

        void LookAt(glm::vec3 position) {
        }

        void Rotate() {}

        void RotateAround() {}

        void Translate() {}
    };
}